package com.aioz.security.service.impl;

import com.aioz.security.common.ResponseResult;
import com.aioz.security.entity.Company;
import com.aioz.security.entity.File;
import com.aioz.security.entity.LoginUser;
import com.aioz.security.entity.User;
import com.aioz.security.mapper.CompanyMapper;
import com.aioz.security.mapper.FileMapper;
import com.aioz.security.mapper.UserMapper;
import com.aioz.security.service.FileService;
import com.aioz.security.utils.ConstantPropertiesUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Aioz
 * @since 2022-09-28
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CompanyMapper companyMapper;

    @Override
    public ResponseResult uploadResume(MultipartFile file) {
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        // 防止重复上传相同名称的文件，覆盖原文件
        String uuid = UUID.randomUUID().toString().replaceAll("-","");
        // 对象键(Key)是对象在存储桶中的唯一标识。
        String key = uuid + file.getOriginalFilename();
        // 对上传的文件分组，根据当前日期
        String dataTime = new DateTime().toString("yyyy/MM/dd");
        key = "/resume/" + dataTime + "/" +key;
        COSClient cosClient = getCOSClient();
        try {
            //获取上传文件输入流
            InputStream inputStream = file.getInputStream();
            ObjectMetadata objectMetadata = new ObjectMetadata();
            PutObjectRequest putObjectRequest =
                    new PutObjectRequest(bucketName, key, inputStream, objectMetadata);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            //返回上传文件路径 https://market-1312547758.cos.ap-beijing.myqcloud.com/resume/b.jpg
            String url = "https://" + bucketName +".cos.ap-beijing.myqcloud.com/" + key;
            File resumeFile = new File();
            resumeFile.setName(file.getOriginalFilename());
            resumeFile.setType("REMOTE");
            resumeFile.setSize(file.getSize());
            resumeFile.setPath(url);
            fileMapper.insert(resumeFile);
            return new ResponseResult(200,url);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseResult(412,"文件上传失败!");
        }
    }

    @Override
    public ResponseResult uploadUserAvatar(MultipartFile file) {
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        // 防止重复上传相同名称的文件，覆盖原文件
        String uuid = UUID.randomUUID().toString().replaceAll("-","");
        // 对象键(Key)是对象在存储桶中的唯一标识。
        String key = uuid + file.getOriginalFilename();
        // 对上传的文件分组，根据当前日期
        String dataTime = new DateTime().toString("yyyy/MM/dd");
        key = "/avatar/" + dataTime + "/" +key;
        COSClient cosClient = getCOSClient();
        try {
            //获取上传文件输入流
            InputStream inputStream = file.getInputStream();
            ObjectMetadata objectMetadata = new ObjectMetadata();
            PutObjectRequest putObjectRequest =
                    new PutObjectRequest(bucketName, key, inputStream, objectMetadata);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            //返回上传文件路径 https://market-1312547758.cos.ap-beijing.myqcloud.com/resume/b.jpg
            String url = "https://" + bucketName +".cos.ap-beijing.myqcloud.com/" + key;
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            User user = userMapper.selectById(loginUser.getUser().getId());
            user.setAvatar(url);
            userMapper.updateById(user);
            return new ResponseResult(200,url);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseResult(412,"文件上传失败!");
        }
    }

    @Override
    public ResponseResult uploadCompanyPhotos(MultipartFile file, String name)  {
        // 使用自己的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        //将图片存储让 CompletableFuture 异步的做
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->{
            // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
            String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
            // 防止重复上传相同名称的文件，覆盖原文件
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            // 对象键(Key)是对象在存储桶中的唯一标识。
            String key = uuid + file.getOriginalFilename();
            // 对上传的文件分组，根据当前日期
            String dataTime = new DateTime().toString("yyyy/MM/dd");
            key = "/company/"+ name + "/"  + dataTime + "/" +key;
            COSClient cosClient = getCOSClient();
            try {
                //获取上传文件输入流
                InputStream inputStream = file.getInputStream();
                ObjectMetadata objectMetadata = new ObjectMetadata();
                PutObjectRequest putObjectRequest =
                new PutObjectRequest(bucketName, key, inputStream, objectMetadata);
                PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
                return "https://" + bucketName +".cos.ap-beijing.myqcloud.com/" + key;
            } catch (Exception e) {
                e.printStackTrace();
                return "文件上传失败!";
            }
        },threadPool);
        //主线程去查企业信息
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        wrapper.eq("foreign_name",name);
        Company company = companyMapper.selectOne(wrapper);
        //等待 CompletableFuture执行完返回 URL 后存入数据库
        String url = null;
        try {
            url = completableFuture.get();
            if("文件上传失败!".equals(url)){
                return new ResponseResult<>(445,"文件上传失败!");
            }
        } catch (Exception e) {
            return new ResponseResult<>(445,"文件上传失败!");
        }
        File photoFile = new File();
        photoFile.setName(file.getOriginalFilename());
        photoFile.setPath(url);
        photoFile.setType("REMOTE");
        photoFile.setCompanyId(company.getId());
        fileMapper.insert(photoFile);
        //关闭线程池
        threadPool.shutdown();
        //返回结果
        return new ResponseResult<>(200,"上传成功");
    }

    @Override
    public ResponseResult getPhotosByCompanyId(Integer companyId) {
        QueryWrapper<File> wrapper = new QueryWrapper<>();
        wrapper.eq("company_id",companyId);
        List<File> files = fileMapper.selectList(wrapper);
        List<String> paths = files.stream().distinct()
                                          .map(File::getPath)
                                          .collect(Collectors.toList());
        return new ResponseResult<>(200,paths);
    }


    public COSClient getCOSClient(){
        String secretId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String secretKey = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        Region region = new Region(ConstantPropertiesUtil.END_POINT);
        ClientConfig clientConfig = new ClientConfig(region);
        // 这里建议设置使用 https 协议
        // 从 5.6.54 版本开始，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }
}
